Exercise (Week 10)
Table of Contents
DUE: 13 May, 2018 23:55
Download the exercise tarball and extract it to a directory in your
home directory at CSE. This tarball contains a file, called Ex08.hs
,
wherein you will do all of your programming.
To test your code, run the following shell commands to open a GHCi session:
$ 3141
newclass starting new subshell for class COMP3141...
$ cabal repl
Resolving dependencies...
Configuring Ex08-1.0...
Preprocessing executable 'Ex08' for Ex08-1.0..
GHCi, version 8.2.2: http://www.haskell.org/ghc/ :? for help
[1 of 1] Compiling Ex08 (Ex08.hs, interpreted)
Ok, one module loaded.
*Ex08> flights SSydney SSeoul
...
Note that you will only need to submit Ex08.hs
, so only make changes
to that file.
Download the exercise tarball and extract it to a directory on
your local machine. This tarball contains a file, called Ex08.hs
,
wherein you will do all of your programming.
To test your code, run the following shell commands to open a GHCi session:
$ stack repl
Configuring GHCi with the following packages: Ex08
Using main module: 1. Package 'Ex08' component exe:Ex08 ...
GHCi, version 8.2.2: http://www.haskell.org/ghc/ :? for help
[1 of 1] Compiling Ex08 (Ex08.hs, interpreted)
Ok, one module loaded.
*Ex08> flights SSydney SSeoul
...
Note that you will only need to submit Ex08.hs
, so only make changes
to that file.
Download the Haskell for Mac project and unzip it somewhere on your
local machine. Open the project in Haskell for Mac, and begin
coding in Ex08.hs
.
Note that you will only need to submit Ex08.hs
, so only make changes
to that file.
1 Flight Planning System
In this exerise, we will work on a basic flight planning system to organise journeys between various sibilant cities in the eastern hemisphere:
data City = Sydney | Shanghai | Seoul | Singapore | Sapporo deriving (Eq, Show, Enum) allCities :: [City] allCities = [Sydney ..]
We shall also define a singleton type version of City
using the following GADT
definition, allowing us to connect the type level to the value level:
data SCity :: City -> * where SSydney :: SCity Sydney SShanghai :: SCity Shanghai SSeoul :: SCity Seoul SSingapore :: SCity Singapore SSapporo :: SCity Sapporo
Note that because the only inhabitant of, for example, SCity Sydney
is SSydney
, this allows us to determine
which type the parameter of SCity
is by pattern matching on its value.
We also define a function to throw away the type level information and return the regular City
corresponding to
an SCity
:
untype :: SCity s -> City untype SSydney = Sydney untype SShanghai = Shanghai untype SSeoul = Seoul untype SSingapore = Singapore untype SSapporo = Sapporo
And, for the other direction, we use Rank-N types to define a function that, given a function that works on
any of the singleton SCity
types, converts it to a function that operates on untyped City
values:
withTyped :: (forall c. SCity c -> b) -> City -> b withTyped f Sydney = f SSydney withTyped f Shanghai = f SShanghai withTyped f Seoul = f SSeoul withTyped f Singapore = f SSingapore withTyped f Sapporo = f SSapporo
Our flight system knows about the following flights, and their starting and finishing points are encoded in their type:
data Flight :: City -> City -> * where NH880 :: Flight Sydney Sapporo SQ222 :: Flight Sydney Singapore KE122 :: Flight Sydney Seoul KE121 :: Flight Seoul Sydney SQ825 :: Flight Shanghai Singapore SQ231 :: Flight Singapore Sydney KE893 :: Flight Seoul Shanghai
A Journey
could consist of a single direct flight, or multiple journeys joined together at a common stop-over point.
Note that the type variable b
here is effectively existentially quantified as it does not appear in the return type:
data Journey :: City -> City -> * where Fly :: Flight a b -> Journey a b Connect :: Journey a b -> Journey b c -> Journey a c
1.1 Part 1 - flight
(3 marks)
Implement a function that, given two SCity
values, returns a flight that connects these two cities, if one exists, or Nothing
otherwise.
flight :: SCity a -> SCity b -> Maybe (Flight a b)
1.2 Part 2 - journeys
(6 marks)
Implement the function journeys
, type signature as below:
journeys :: [City] -> SCity a -> SCity b -> [Journey a b]
journeys cs a b
returns all journeys starting in a
and ending in b
, starting with the most direct one, which can make
intermediate stops only at cities listed in cs
.
Examples:
*Ex08> journeys [Shanghai, Singapore] SSeoul SSydney [Fly KE121 ,Connect (Fly KE893) (Connect (Fly SQ825) (Fly SQ231)) ,Connect (Connect (Fly KE893) (Fly SQ825)) (Fly SQ231) ] *Ex08> journeys [Sydney, Singapore] SSingapore SSydney [Fly SQ231 ,Connect (Fly SQ231) (Connect (Fly SQ222) (Fly SQ231)) ,Connect (Connect (Fly SQ231) (Fly SQ222)) (Fly SQ231) ]
The list you must return will consist of:
- The direct flight, if one exists, from the starting point to the ending point.
- For each city
c
in the given list of stop-over cities, every journey from the starting point toc
(withc
removed from the list of stop-overs),Connect
-ed to every journey fromc
to the ending point. List comprehensions can be used to some effect here. Also, the functiondelete
fromData.List
can be used to remove the city from the list of stop-overs on each recursive call. Use theuntype
andwithTyped
functions to convert between the singletonSCity
and the plainCity
as needed.
2 Submission instructions
$ give cs3141 Ex08 Ex08.hs
on a CSE terminal, or by using the give
web interface. Your file must be named Ex08.hs
(case-sensitive!).
A dry-run test will partially autotest your solution at submission time. To get full marks, you will need to
perform further testing yourself.